Hands-on Exercise 3.2: Programming Animated Statistical Graphics with R

Author

Sheryl Ann Tan Yi-Shi

Published

January 26, 2025

Modified

January 26, 2025

1.0 Getting Started

1.1 Loading the R Packages

The following code chunk imports and loads the following R packages:

R Package Description
gifski Converts image frames into high-quality GIF animations.
gganimate A ggplot extension for creating animated statistical graphs.
gapminder An excerpt of the data available at Gapminder.org. The country_colors scheme will be used in this exercise.
pacman::p_load(readxl, gifski, gapminder,
               plotly, gganimate, tidyverse)

1.2 Importing the Data

The following code chunk is used to import the Data worksheet from GlobalPopulation Excel workbook into R:

col <- c("Country", "Continent")
globalPop <- read_xls("data/GlobalPopulation.xls",
                      sheet="Data") %>%
  mutate_each_(funs(factor(.)), col) %>%
  mutate(Year = as.integer(Year))

mutate_each( ) of the dplyr package is used to convert all data type into factor. In R, a factor is a data type that is used to represent categorical data.

However, mutate_each( ) and funs( ) were deprecated in dplyr 0.7.0 and dplyr 0.8.0 respectively. As such, the code chunk will be re-written using mutate_at( ).

col <- c("Country", "Continent")
globalPop <- read_xls("data/GlobalPopulation.xls",
                      sheet="Data") %>%
  mutate_at(col, as.factor) %>%
  mutate(Year = as.integer(Year))

Alternatively, across( ) can also be used to derive the same outputs.

col <- c("Country", "Continent")
globalPop <- read_xls("data/GlobalPopulation.xls",
                      sheet="Data") %>%
  mutate(across(col, as.factor)) %>%
  mutate(Year = as.integer(Year))

2.0 Animated Data Visualisation: gganimate Methods

The table below describes some of the grammar classes under gganimate:

Grammar Class Description
transition_*( ) Defines how the data should be spread out and how it relates itself across time.
view_*( ) Defines how the positional scales should change along the animation
shadow_*( ) Defines how data from other points in time should be presented in the given point in time.
enter_*( ) / exit_*( ) Defines how new data should appear and how old data should disappear during the course of animation.
ease_aes( ) Defines how different aesthetics should be eased during transitions.

2.1 Building a Static Population Bubble Plot

The code chunk below uses the basic ggplot2 functions to create a static bubble plot:

ggplot(globalPop, aes(x = Old, y = Young, 
                      size = Population, 
                      colour = Country)) +
  geom_point(alpha = 0.7, 
             show.legend = FALSE) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(title = 'Year: {frame_time}', 
       x = '% Aged', 
       y = '% Young') 

2.2 Building an Animated Bubble Plot

  1. transition_time( ) is used to create the transition through distinct states of time.

  2. ease_aes( ) is used to control the easing of aesthetics. The default is linear. Other methods include quadratic, cubic, quartic, quintic, sine, circular, exponential, elastic, back, and bounce. For example, cubic-in-out would start with the animation slowly easing in, speeding up in the middle and then slowly easing out.

ggplot(globalPop, aes(x = Old, y = Young, 
                      size = Population, 
                      colour = Country)) +
  geom_point(alpha = 0.7, 
             show.legend = FALSE) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(title = 'Year: {frame_time}', 
       x = '% Aged', 
       y = '% Young') +
  transition_time(Year) +       
  ease_aes('linear')          

3.0 Animated Data Visualisation: plotly

3.1 Building an Animated Bubble Plot: ggplotly( ) Method

gg <- ggplot(globalPop, 
       aes(x = Old, 
           y = Young, 
           size = Population, 
           colour = Country)) +
  geom_point(aes(size = Population,
                 frame = Year),
             alpha = 0.7, 
             show.legend = FALSE) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(x = '% Aged', 
       y = '% Young')

ggplotly(gg)

The animated bubble plot includes a play/pause button and a slider to control the animation.

Although show.legend = FALSE was used, the legend still appears on the plot. Hence, theme(legend.position='none') will be used to replace the affected code chunk.

gg <- ggplot(globalPop, 
       aes(x = Old, 
           y = Young, 
           size = Population, 
           colour = Country)) +
  geom_point(aes(size = Population,
                 frame = Year),
             alpha = 0.7) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(x = '% Aged', 
       y = '% Young') + 
  theme(legend.position='none')

ggplotly(gg)

3.2 Building an Animated Bubble Plot: plot_ly( ) Method

bp <- globalPop %>%
  plot_ly(x = ~Old, 
          y = ~Young, 
          size = ~Population, 
          color = ~Continent,
          sizes = c(2, 100),
          frame = ~Year, 
          text = ~Country, 
          hoverinfo = "text",
          type = 'scatter',
          mode = 'markers'
          ) %>%
  layout(showlegend = FALSE)
bp

4.0 Exploring Other Animated Visualisations

The code chunk below calculates the total population for each continent by year and creates an animated bar chart to visualises how the population size change across the year for each continent.

continent_pop <- globalPop %>%
  group_by(Year, Continent) %>%
  summarise(Population = sum(Population, na.rm = TRUE), .groups = "drop") %>%
  arrange(Year, desc(Population))

animated_bar_continent <- ggplot(continent_pop, aes(x = Population, y = reorder(Continent, Population))) +
  geom_bar(stat = "identity") +
  scale_x_continuous(labels = scales::comma) +
  labs(
    title = "Population by Continent: Year {frame_time}",
    x = "Population",
    y = NULL
  ) +
  theme_minimal() +
  theme(
    axis.text.y = element_text(size = 12),
    legend.position = "none"  # Remove the legend
  ) +
  transition_time(Year) +
  ease_aes("linear")


animate(animated_bar_continent, nframes = 100, fps = 10)

The code chunk below creates an animated bar chart that shows the changes in population by continent over time.

continent_pop <- globalPop %>%
  group_by(Year, Continent) %>%
  summarise(Population = sum(Population, na.rm = TRUE), .groups = "drop") %>%
  arrange(Year, desc(Population))

animated_bar_continent <- plot_ly(
  data = continent_pop,
  x = ~Population,
  y = ~reorder(Continent, Population),
  frame = ~Year,  # Animate by year
  type = 'bar',
  orientation = 'h',  # Horizontal bars
  marker = list(color = ~as.factor(Continent)),  # Color by continent
  hoverinfo = "none"  # Disable hover text
) %>%
  layout(
    title = "Population by Continent Over Time",
    xaxis = list(title = "Population", tickformat = ","),
    yaxis = list(title = ""),
    showlegend = FALSE  # Remove legend
  )

animated_bar_continent

5.0 References

5.1 Disclaimer

This document includes content written with the assistance of ChatGPT, which was used for grammar and code correction, and the explanation of arguments for the various packages.